package cn.wen.xframe.monitor;

import java.lang.management.ThreadMXBean;
import java.text.DecimalFormat;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;

import sun.management.ManagementFactory;

import cn.wen.bases.framework.struts.action.ActionSupport;
import cn.wen.bases.framework.struts.action.model.AbstractModel;

/**
 * Title：线程信息
 * <p>
 * Description：
 * <p>
 * Copyright：Copyright (c) 2010-2012
 * 
 * @author <a href="mailto:ct_wen@qq.com">ctwen</a>, 温承瑭
 * @version Revision：1.0 Date：2012/12/2 Description：初完成。
 *          <p>
 */
public class ThreadAction extends ActionSupport {

    private ThreadModel model = new ThreadModel();

    @Override
    public Object getModel() {
	return model;
    }

    @Override
    public String execute() throws Exception {
	initThreadMXBean();

	StringBuilder sb = new StringBuilder();
	for (Thread t : Thread.getAllStackTraces().keySet()) {
	    if (!isAllowThread(t)) continue;

	    String name = t.getName();
	    String daemon = t.isDaemon() ? "yes" : "no";

	    sb.append("<tr>\n");
	    sb.append("  <td>\n");
	    sb.append("    <a class='tooltip'>\n");
	    sb.append("      <em>\n");
	    for (StackTraceElement stack : t.getStackTrace()) {
		sb.append("      " + stack.toString() + "<br>\n");
	    }
	    sb.append("      </em>\n");
	    // 名称
	    sb.append("      " + name);
	    sb.append("    </a>\n");
	    sb.append("  </td>\n");
	    // 是否为后台线程
	    sb.append("  <td align='center'>" + daemon + "</td>\n");
	    // 优先权
	    sb.append("  <td align='right'>" + t.getPriority() + "</td>\n");
	    // 状态
	    sb.append("  <td state>" + t.getState() + "</td>\n");
	    // 当前被执行的方法
	    sb.append("  <td>" + t.getStackTrace()[0] + "</td>\n");
	    // CPU使用时间 (ms)
	    sb.append("  <td>" + getThreadCpuTime(t) + "</td>\n");
	    // 用户时间(ms)
	    sb.append("  <td>" + getThreadUserTime(t) + "</td>\n");
	    // 杀线程
	    sb.append("  <td align='center' class='noPrint'>\n");
	    sb.append("    <a href='javascript:void(0);' tid='" + t.getId() + "'>" + name + "</a>\n");
	    sb.append("  </td>\n");

	    sb.append("</tr>\n");
	}
	model.threadGridHtml = sb;

	return "grid";
    }

    /**
     * 是否输出指定线程。
     */
    private boolean isAllowThread(Thread t) {
	if (null == t) {
	    return false;
	}

	if (ArrayUtils.isEmpty(t.getStackTrace())) {
	    return false; // 剔除没有堆栈跟踪的线程。
	}

	if (StringUtils.isNotBlank(model.state)) {
	    if (!model.state.equals(t.getState().name())) {
		return false; // 剔除非指定状态的线程。
	    }
	}

	if (StringUtils.isNotBlank(model.key)) {
	    for (StackTraceElement stack : t.getStackTrace()) {
		if (!stack.toString().contains(model.key)) continue;
		return true; // 剔除非关键堆栈的线程。
	    }
	}

	return false;
    }

    /**
     * 终止线程。
     */
    public String interrupt() {
	// I know that it is unsafe and the user has been warned
	for (Thread t : Thread.getAllStackTraces().keySet()) {
	    if (t.getId() == model.id) t.interrupt();
	}
	return NONE;
    }

    private ThreadMXBean threadMXBean;

    /**
     * 初始线程管理接口
     */
    private ThreadMXBean initThreadMXBean() {
	if (null == threadMXBean) {
	    threadMXBean = ManagementFactory.getThreadMXBean();
	}
	return threadMXBean;
    }

    private String getThreadCpuTime(Thread t) {
	return getNS2MS(threadMXBean.getThreadCpuTime(t.getId()));
    }

    private String getThreadUserTime(Thread t) {
	return getNS2MS(threadMXBean.getThreadUserTime(t.getId()));
    }

    private DecimalFormat ndf = new DecimalFormat("#,##0.#");

    /**
     * 纳秒转毫秒。
     */
    private String getNS2MS(long ns) {
	return ndf.format(ns / Math.pow(1000, 2));
    }

}

class ThreadModel extends AbstractModel {

    /**
     * 线程编号
     */
    long id;

    /**
     * 线程状态
     */
    String state = ""; // java.lang.Thread.State.RUNNABLE.toString();

    /**
     * 堆栈跟踪关键字
     */
    String key = "cn.wen.forever";

    public long getId() {
	return id;
    }

    public void setId(long id) {
	this.id = id;
    }

    public String getState() {
	return state;
    }

    public void setState(String state) {
	this.state = state;
    }

    public String getKey() {
	return key;
    }

    public void setKey(String key) {
	this.key = key;
    }

    /**
     * 线程信息HTML表格体
     */
    StringBuilder threadGridHtml;

    public StringBuilder getThreadGridHtml() {
	return threadGridHtml;
    }
}
